#ifndef __M_EXCHAGE_H__
#define __M_EXCHAGE_H__
#include"../mqcommon/mq_helper.hpp"
#include"../mqcommon/mq_logger.hpp"
#include"../mqcommon/mq_msg.pb.h"
#include"../mqcommon/mq_proto.pb.h"
#include <google/protobuf/map.h>
#include<string>
#include<iostream>
#include<unordered_map>
#include<memory>
namespace bitmq{
    //1、定义一个交换机数据类
    class Exchage{
        public:
       
        std::string _name;//交换机名称
        ExchageType _type;//交换机类型
        bool _durable;//是否持久化
        bool _auto_delete;//是否自动删除
        google::protobuf::Map<std::string, std::string> _args;//其他参数
        public:
        using ptr=std::shared_ptr<Exchage>;
        Exchage(){}
        Exchage(std::string name,ExchageType type,bool durable,bool auto_delete,const google::protobuf::Map<std::string, std::string>& args):
        _name(name),_type(type),_durable(durable),_auto_delete(auto_delete),_args(args){printf("exchange_type: %d\n", _type);}
        //key=val&key=val   这种格式传入并进行存储
        void setArgs(const std::string&str_args)
        {
            std::vector<std::string> sub_args;
            bitmq::StrHelper::split(str_args,"&",sub_args);
            for(auto&str:sub_args)
            {
                size_t pos=str.find('=');
                std::string key=str.substr(0,pos);
                std::string val=str.substr(pos+1);
                _args[key]=val;
            }
        }
        //将args中的数据序列化后返回一个字符串  key=val&key=val&key=val&key=val&
        std::string getArgs()
        {
            std::string kvs;
            for(auto start=_args.begin();start!=_args.end();start++)
            {
                kvs+=start->first+"="+start->second+"&";
            }
            return kvs;
        }
    };



    //2、定义一个交换机数据持久化管理类--存储在sqlite数据库中的
    using ExchageMap=std::unordered_map<std::string,Exchage::ptr>;
    class ExchageMapper{
        public:
        //ExchageMapper(){}
        ExchageMapper(const std::string&dbfile):_db(dbfile){
            std::string path=bitmq::FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);
            assert(_db.open());
            createTable();
            
        }
        void createTable()//创建交换机数据表
        {
            
            #define CREATE_TABLE "create table if not exists exchage_table(name varchar(32) primary key, type int, durable int, auto_delete int, args varchar(128));"
            bool ret=_db.exec(CREATE_TABLE,nullptr,nullptr);
            if(!ret)
            {
                DLOG("创建持久化数据表失败！");
                abort();//直接退出程序
            }
            //std::cout<<"建表成功"<<std::endl;

        }
        void removeTable()//删除交换机数据表
        {
            std::string sql= "drop table if exists exchage_table;";
            bool ret=_db.exec(sql.c_str(),nullptr,nullptr);
            if(!ret)
            {
                DLOG("删除交换机数据表失败!");
                abort();
            }
        }
        bool insert(Exchage::ptr&exp)//向数据表中插入交换机数据
        {
            // std::stringstream ss;
            // ss<<"insert into exchage_table values(";
            // ss<<"'"<<exp->_name<<"',";
            // ss<<exp->_type<<",";
            // ss<<exp->_durable<<",";
            // ss<<exp->_auto_delete<<",";
            // ss<<"'"<<exp->getArgs()<<"');";
            // return _db.exec(ss.str(),nullptr,nullptr);
            std::stringstream ss;
                ss << "insert into exchage_table values(";
                ss << "'" << exp->_name << "', ";
                ss << exp->_type << ", ";
                ss << exp->_durable << ", ";
                ss << exp->_auto_delete << ", ";
                ss << "'" << exp->getArgs() << "');";
                
                return _db.exec(ss.str(), nullptr, nullptr);
        }
        void remove(const std::string&name)//移除交换机数据
        {
            std::stringstream ss;
            ss<<"delete from exchage_table where name=";
            ss<<"'"<<name<<"';";
            _db.exec(ss.str(),nullptr,nullptr);
        }
       
        ExchageMap recovery()//获取/恢复所有交换机数据
        {
            ExchageMap result;
            std::string sql = "select name, type, durable, auto_delete, args from exchage_table;";
            _db.exec(sql,selectCallback,&result);
            return result;
        }
        private:
        static int selectCallback(void*arg,int numcol,char**row,char**fields)
        {
            ExchageMap* result=(ExchageMap*)arg;
            auto exp=std::make_shared<Exchage>();
            exp->_name=row[0];
            exp->_type=(bitmq::ExchageType)std::stoi(row[1]);
            exp->_durable=(bool)std::stoi(row[2]);
            exp->_auto_delete=(bool)std::stoi(row[3]);
            if(row[4])exp->setArgs(row[4]);
            result->insert(std::make_pair(exp->_name,exp));
            return 0;
        }
        bitmq::Sqlite _db;
    };





    //3、定义一个交换机内存管理类--向外提供的接口--
    class ExchageManager{
        public:
        using ptr=std::shared_ptr<ExchageManager>;
        ExchageManager( std::string dbfile):_mapper(dbfile){
            _exchages=_mapper.recovery();
        }
        bool declareExchage(const std::string name,ExchageType type,bool durable,bool auto_delete, const google::protobuf::Map<std::string, std::string>&args)//声明交换机
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_exchages.find(name);
            if(it!=_exchages.end())
            {
                return true;
            }
            auto exp=std::make_shared<Exchage>(name,type,durable,auto_delete,args);

            if(exp->_durable==true)
            {
                bool ret=_mapper.insert(exp);
                if(!ret)return false;
            }
            _exchages.insert(std::make_pair(name,exp));
            return true;
        }
        void deleteExchage(const std::string&name)//删除交换机
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_exchages.find(name);
            if(it==_exchages.end())
            {
                return;
            }
            if(it->second->_durable==true)_mapper.remove(name);
            _exchages.erase(name);
        }
        Exchage::ptr selectExchage(const std::string name)//获取指定交换机的信息
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_exchages.find(name);
            if(it==_exchages.end())
            {
                return Exchage::ptr();
            }
            return it->second;
        }
        size_t size()
        {
            return _exchages.size();
        }
        bool exists(const std::string&name)//判断交换机是否存在
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it=_exchages.find(name);
            if(it!=_exchages.end())
            {
                return true;
            }
            return false;
        }
        void clear()//清除交换机所有数据
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();
            _exchages.clear();
        }
        private:
        std::mutex _mutex;
        ExchageMapper _mapper;
        std::unordered_map<std::string,Exchage::ptr> _exchages;
    };
}
#endif